package withouther.system.plugins.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;
import withouther.system.core.base.BaseServiceImpl;
import withouther.system.core.util.SecurityUtil;
import withouther.system.core.util.page.PageQuery;
import withouther.system.core.util.page.PageUtils;

import withouther.system.plugins.system.entity.Menu;
import withouther.system.plugins.system.entity.Organization;
import withouther.system.plugins.system.entity.dto.MenuDto;
import withouther.system.plugins.system.entity.dto.MetaVo;
import withouther.system.plugins.system.entity.dto.RouterVo;
import withouther.system.plugins.system.mapper.MenuMapper;
import withouther.system.plugins.system.service.MenuService;

import javax.annotation.Resource;


@Service("MenuService")
@Slf4j
@CacheConfig(cacheNames = "menu")
public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, Menu> implements MenuService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<Menu> page = this.page(
                new PageQuery<Menu>().getPage(params),
                new QueryWrapper<Menu>()
        );
        return new PageUtils(page);
    }

    @Override
    @CacheEvict(allEntries = true)
    public Menu addMenu(Menu menu) {
        if(isMenuName(menu)){
            throw new RuntimeException("name");
        }
        this.save(menu);
        return menu;
    }

    @Override
    @Cacheable(key = "'tree'")
    public Object getMenuTree(List<Menu> menus) {
        List<Map<String,Object>> list = new LinkedList<>();
        menus.forEach(menu -> {
                    if (menu!=null){
                        QueryWrapper queryWrapper = new QueryWrapper();
                        queryWrapper.eq("parent_id",menu.getId());
                        List<Menu> menuList = this.baseMapper.selectList(queryWrapper);
                        //List<Menu> menuList = menuRepository.findByPid(menu.getId());
                        Map<String,Object> map = new HashMap<>(16);
                        map.put("id",menu.getId());
                        map.put("label",menu.getName());
                        if(menuList != null && menuList.size() != 0){
                            map.put("children",getMenuTree(menuList));
                        }
                        list.add(map);
                    }
                }
        );
        return list;
    }

    @Override
    @Cacheable(key = "#p0")
    public List<Menu> findByParentId(long parentId) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("parent_id",parentId);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Map<String,Object> buildTree(List<Menu> menuDtos) {
        List<Menu> trees = new ArrayList<>();
        Set<Long> ids = new HashSet<>();
        for (Menu menu : menuDtos) {
            if (menu.getParentId() == 0) {
                trees.add(menu);
            }
            for (Menu it : menuDtos) {
                if (it.getParentId().equals(menu.getId())) {
                    if (menu.getChildren() == null) {
                        menu.setChildren(new ArrayList<>());
                    }
                    menu.getChildren().add(it);
                    ids.add(it.getId());
                }
            }
        }
        Map<String,Object> map = new HashMap<>(2);
        if(trees.size() == 0){
            trees = menuDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
        }
        map.put("list",trees);
        map.put("totalElements", menuDtos.size());
        return map;
    }

    @Override
    public List<Menu> listMenu(Map<String, Object> paramMap) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.allEq(paramMap, false);
        List<Menu> menus =  this.list(queryWrapper);
        return menus;
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean updateMenu(Menu resources) {

        Menu menu = this.getById(resources.getId());
        if (menu == null) {
            return false;
        }
        isMenuName(menu);
        this.updateById(resources);
        return false;
    }


    private boolean isMenuName(Menu menu) {
        if ("2".equals(menu.getResourceType())) {
            return false;
        }
        String name = menu.getName();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(StrUtil.isNotEmpty(name), "name", name);
        Menu amenu =  this.getOne(queryWrapper);
        boolean isMenu = amenu != null;
        boolean isMenuUpd = menu.getId() != null && menu.getId() > 0;
        if (isMenuUpd && isMenu && (!amenu.getId().equals(menu.getId()))) {
            return true;
        } else if (isMenu) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    public boolean removeByIds(List<Long> ids) {
        for (Long id : ids) {
            deleteTreeById(id);
        }
        return true;
    }

    @Override
    public List<Menu> findPermsByUserId(Long userId) {
        log.info("用户id为：" + userId);

        if (SecurityUtil.isAdmin(userId)) {
            return this.list();
        }
        return this.baseMapper.findPermsByUserId(userId);
    }

    @Override
    @Cacheable(key = "'roleId:'+#p0")
    public List<Menu> selectRoleMenusByRoleId(Long roleId) {
        return this.baseMapper.selectRoleMenusByRoleId(roleId);
    }

    @Override
    public List<RouterVo> buildMenus(List<Menu> amenus) {
        List<Menu> menus = builTree(amenus);
        List<RouterVo> routers = buildMenusTree(menus);
        return routers;
    }
    private List<RouterVo> buildMenusTree(List<Menu> amenus) {
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (Menu menu : amenus)
        {
            if ("2".equals(menu.getResourceType())) {
                continue;
            }
            RouterVo router = RouterVo.builder()
                    .hidden(menu.getAvailable() == 0)
                    .name(StringUtils.capitalize(menu.getComponentName()))
                    .path(menu.getUrl())
                    .component(StrUtil.isEmpty(menu.getComponent()) ? "Layout" : menu.getComponent())
                    .meta(MetaVo.builder().title(menu.getName()).icon(menu.getIcon()).build())
                    .build();
            List<Menu> aMenus = menu.getChildren();
            if ("0".equals(menu.getResourceType())) {
                router.setRedirect("noRedirect");
                router.setAlwaysShow(true);
            }
            if (!aMenus.isEmpty() && aMenus.size() > 0)
            {
                router.setChildren(buildMenusTree(aMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 根据父节点的ID获取所有子节点
     *
     * @param menus 分类表
     * @param parentId 传入的父节点ID
     * @return String
     */
    private List<Menu> getChildPerms(List<Menu> menus, int parentId)
    {
        List<Menu> returnList = new ArrayList<Menu>();

        return returnList;
    }

    public List<Menu> builTree(List<Menu> menus){
        List<Menu> treeMenus =new  ArrayList<Menu>();
        for(Menu menuNode : getRootNode(menus)) {
            menuNode=buildChilTree(menuNode, menus);
            treeMenus.add(menuNode);
        }
        return treeMenus;
    }

    //递归，建立子树形结构
    private Menu buildChilTree(Menu pNode, List<Menu> menus){
        List<Menu> chilMenus =new  ArrayList<Menu>();
        for(Menu menuNode : menus) {
            if(menuNode.getParentId().equals(pNode.getId())) {
                chilMenus.add(buildChilTree(menuNode, menus));
            }
        }
        pNode.setChildren(chilMenus);
        return pNode;
    }

    //获取根节点
    private List<Menu> getRootNode(List<Menu> menus) {
        List<Menu> rootMenuLists =new  ArrayList<Menu>();
        for(Menu menuNode : menus) {
            if(menuNode.getParentId() == 0) {
                rootMenuLists.add(menuNode);
            }
        }
        return rootMenuLists;
    }
    private boolean deleteTreeById(Long id) {
        Menu menu = this.getById(id);
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", menu.getId());
        List<Menu> menus = this.list(queryWrapper);
        if (menus != null) {
            for (Menu amenu : menus) {
                deleteTreeById(amenu.getId());
            }
        }
        this.removeById(id);
        return true;
    }


}